Cloudflare の HTTP リクエストログを Amazon S3 に出力して Amazon Athena で分析してみた
ウィスキー、シガー、パイプをこよなく愛する大栗です。
最近 Cloudflare を触っています。運用を考えるとアクセス状況の把握が必要になります。標準で分析ダッシュボードも有るのですが、詳細ログを分析したくなることがあります。今回は HTTP リクエストのログを S3 へ出力して Amazon Athena で分析してみます。
Cloudflare Logpush
Cloudflare はログを確認するための手段を複数用意しています。今回はこの中の Logpush に焦点を当てます。なお Logpush は Enterprise Plan での提供となっています。
- Logpush: 外部のストレージサービスへバッチでログをプッシュします
- Logpull: REST API でリクエストログを取得します
- Instant Logs: ダッシュボードかコマンドラインからトラフィックのライブストリームにアクセスできます
Logpush はログの各バッチを改行区切り JSON(いわゆる NDJSON)を gzip ファイルとして、通常 1 分以内に配信します。このバッチはファイルごとに 100,000 レコード以下になります。Logpush は 1 分に複数ファイルを配信する場合もあります。1
配信先としては外部のストレージやモニタリング、SIEM 等へ出力できます。標準では以下のサービスに対応しています。
- Amazon S3
- S3-compatible endpoints
- Datadog
- Google Cloud Storage
- Microsoft Azure Blob Storage
- New Relic
- Splunk
- Sumo Logic
上記以外に Google BigQuery へ出力するツールや、API を介してそれ以外を構成することが可能です。
やってみる
今回は Logpush で HTTP リクエストのログを Amazon S3 へ配信して、結果を Amazon Athena で分析してみようと思います。ざっくりと下図の様になります。Cloudflare から Logpush で Amazon S3 へ配信して、Amazon Athena を使って SQL で分析します。
手順の前に Amazon S3 に保存用のバケットを準備しておきます。今回は東京リージョン(ap-northeast-1)に作成しました。
Cloudflare Logpush を構成する
まずは Cloudflare で Logpush の設定を行います。
各 Web サイトのページで、左のメニューから [Analytics]-[Logs] を開きます。
今回は HTTP リクエストのログを対象にするため、HTTP requests
を選択してNext
をクリックします。
配信するログのフィールドを選択します。今回はデフォルトのフィールド2を使用しますが、All fields
をチェックして全フィールドの出力を推奨します。そのままNext
をクリックします。必要に応じてフィールドを追加しましょう。
ログの配信先を選択します。今回は Amazon S3 を選択して、Next
をクリックします。
配信先の情報を記載します。
- Bucket path: / 形式で入力
- Daily subfolders:
Yes, automatically organize logs in daily subfolders
クエリを楽にするためにログを毎日のサブフォルダに自動的に整理します - Encryption constraint in bucket policy:
No
情報を入力するとGrant Cloudflare access to upload files to your bucket
の項に必要なバケットポリシーが表示されるのでコピーします。一番下のAmazon S3 bucket permissions
のリンクから Amazon S3 のコンソールを開きます。
Amazon S3 のコンソールでPermissions
(アクセス許可)タブを開き、Bucket policy
(バケットポリシー)のEdit
(編集)をクリックします。
Logpush で表示されたバケットポリシーを Policy の欄にペーストして、Save changes
をクリックします。バケットポリシーが既存で必要なものがある場合は、内容をマージしてください。
Cloudflare の画面に戻り、Validate access
をクリックします。
S3 バケットの所有権を確認します。Logpush で書き込んだトークンの内容を確認するために、リンクにある S3 オブジェクトにアクセスします。
Open
をクリックして内容を確認し、トークンの内容をコピーします。
コピーしたトークンの内容をOwnership token
の欄にペーストして、Push
をクリックします。
Amazon S3 への Logpush が構成されました。
サイトへアクセスするとログファイルが配信されます。
ファイルの中身な以下のようになっています。
{"ClientIP":"2001:0db8:0001:0002:0003:0004:0005:1234","ClientRequestHost":"cf.example.net","ClientRequestMethod":"GET","ClientRequestURI":"/","EdgeEndTimestamp":"2022-04-05T00:24:29Z","EdgeResponseBytes":4200,"EdgeResponseStatus":403,"EdgeStartTimestamp":"2022-04-05T00:24:29Z","RayID":"1234241e4a89ef86"} {"ClientIP":"2001:0db8:0001:0002:0003:0004:0005:1234","ClientRequestHost":"cf.example.net","ClientRequestMethod":"GET","ClientRequestURI":"/cdn-cgi/bm/cv/669835187/api.js","EdgeEndTimestamp":"2022-04-05T00:24:29Z","EdgeResponseBytes":9690,"EdgeResponseStatus":200,"EdgeStartTimestamp":"2022-04-05T00:24:29Z","RayID":"1234241f9b4aef86"} {"ClientIP":"2001:0db8:0001:0002:0003:0004:0005:1234","ClientRequestHost":"cf.example.net","ClientRequestMethod":"GET","ClientRequestURI":"/favicon.ico","EdgeEndTimestamp":"2022-04-05T00:24:29Z","EdgeResponseBytes":3858,"EdgeResponseStatus":403,"EdgeStartTimestamp":"2022-04-05T00:24:29Z","RayID":"123424219c95ef86"} {"ClientIP":"2001:0db8:0001:0002:0003:0004:0005:1234","ClientRequestHost":"cf.example.net","ClientRequestMethod":"POST","ClientRequestURI":"/cdn-cgi/bm/cv/result?req_id=6f6e249ef86","EdgeEndTimestamp":"2022-04-05T00:24:29Z","EdgeResponseBytes":666,"EdgeResponseStatus":204,"EdgeStartTimestamp":"2022-04-05T00:24:29Z","RayID":"123424217c88ef86"}
Amazon Athena でテーブルを作成する
次に Amazon S3 のデータを Amazon Athena で分析できるようにテーブルを作成します。
Amazon Athena のコンソールでExplore the query editor
(クエリエディタを詳しく確認する)をクリックします。
初回の利用でクエリ結果の保存場所を設定していない場合にはView settings
(設定を表示)をクリックします。
Manage
(管理)をクリックします。
クエリ結果を保存する S3 のパスを入力してます。ここでは Athena と同じリージョンのバケットを選択してください。そしてSave
(保存)をクリックします。
この様にクエリ結果の場所が設定されました。次はEditor
(エディタ)タブに遷移してテーブルを作成します。
まずデータベースを作成します。以下の SQL を実行して、cloudflare_logpush
というデータベースを作成します。クエリエディタに SQL を入力したらRun
をクリックします。
CREATE DATABASE IF NOT EXISTS cloudflare_logpush COMMENT 'Logs from Cloudflare logpush';
実行するとCompleted
になり、Query successful.
と表示されます。
テーブルを作成します。以下の SQL を実行して、cloudflare_http_request_logs
というテーブルを作成します。クエリエディタに SQL を入力したらRun
をクリックします。なお、SQL 中の <bucket_name> と <file_to_path> は Cloudflare の Logpush で設定した配信先の内容に置き換えて実行してください。ここでは Partition Projection を使用して、保存フォルダでパーティショニングしています。
CREATE EXTERNAL TABLE IF NOT EXISTS `cloudflare_logpush`.`cloudflare_http_request_logs` ( `clientip` string, `clientrequesthost` string, `clientrequestmethod` string, `clientrequesturi` string, `edgeendtimestamp` string, `edgeresponsebytes` int, `edgeresponsestatus` string, `edgestarttimestamp` string, `rayid` string ) PARTITIONED BY ( `requestdate` string) ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe' LOCATION 's3://<bucket_name>/<file_to_path>' TBLPROPERTIES ( 'projection.enabled' = 'true', 'projection.requestdate.type' = 'date', 'projection.requestdate.range' = '19920101,NOW', 'projection.requestdate.format' = 'yyyyMMdd', 'projection.requestdate.interval' = '1', 'projection.requestdate.interval.unit' = 'DAYS', 'storage.location.template' = 's3://<bucket_name>/<file_to_path>/${requestdate}', 'classification'='json', 'compressionType'='gzip', 'typeOfData'='file');
実行するとCompleted
になり、Query successful.
と表示されます。
作成したテーブルで問題なくデータを参照できるか確認します。Tables
のcloudflare_logpush
の右にあるメニューからPreview Table
をクリックします。
テーブルが問題なく作成されていればプレビュー結果が表示されます。
Amazon Athena でログを分析する
ログを分析してみます。分析内容はドキュメントの内容を抜粋して jq から SQL に変更したもので実施してみます。
フィールドの集約
jq では以下のようにClientRequestURI
が一致したものの数をカウントしてソートしています。
$ jq -r .ClientRequestURI logs.json | sort -n | uniq -c | sort -n | tail 2 /nginx-logo.png 2 /poweredby.png 2 /testagain 3 /favicon.ico 3 /testing 3 /testing123 6 /test 7 /testing1234 10 /cdn-cgi/nexp/dok3v=1613a3a185/cloudflare/rocket.js 54 / SQL で同様の分析を行う場合は、以下のようになります。 <img src="https://cdn-ssl-devio-img.classmethod.jp/wp-content/uploads/2022/04/24049bdcae252f1592dcdd8cb942e6d4.png" alt="" width="850" height="696" class="alignnone size-full wp-image-862026" /> #### フィールドのフィルタリング jq では以下のように`ClientRequestURI`が一致したものの数をカウントしてソートしています。 $ jq 'select(.OriginResponseStatus == 502) | .ClientRequestURI' logs.json | sort -n | uniq -c | sort -n | tail 1 "/favicon.ico" 1 "/testing" 3 "/testing123" 6 "/test" 6 "/testing1234" 18 "/"
SQL で同様の分析を行う場合は、以下のようになります。実データではステータス502
のデータが少なかったため 302
で置き換えています。
SELECT COUNT("clientrequesturi") as count, "clientrequesturi" FROM "cloudflare_http_request_logs" WHERE "cloudflare_http_request_logs"."edgeresponsestatus" = '302' GROUP BY "clientrequesturi" ORDER BY count;
さいごに
Cloudflare のログは別のプラットフォームを使用して詳細に分析が可能になっています。今回は Amazon S3 にログを配信して、Amazon Athena で分析をしてみました。Amazon S3 の logpush はアクセスキーを発行する必要がなくセキュアに手軽に連携できます。
今回は Athena で分析してみましたが S3 にログがあればデータ処理は簡単なので、もうひと手間入れるだけで可視化ができるので Cloudflare の稼働状況ダッシュボードも作成できます。Cloudflare の本格的な運用を行うためには Logpush は必須の機能と言えるのでお試し頂ければと思います。
- 2020年前半以前は 5 分ごとにログを配信(Logpush v1)していました。現在は Logpush v2 がデフォルトの設定になっていますが、古い設定の場合は Logpush API を使用して v2 にアップグレードします。 ↩
- HTTP requests のログのフィールドの詳細はHTTP requestsを参照してください。 ↩